
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.Text;

using Swaf;
using Swaf.BizObj;
using Swaf.BizRule;
using Swaf.Container;
using Swaf.Logging;

namespace Swaf.BizRule
{
	/// <summary>
	/// This class provides the ability to log the input and results of any rule call
	/// via the log decorator.  It is controlled by adding the log attribute to a rule 
	/// declaration with a value of true to enable logging.  Optionally, a logLevel and/or 
	/// logExceptionsOnly attribute can be added to further control teh logging behavior.  
	/// If these optional attributes are not provided, the default logging level will be used
	/// as defined in the application feature file and all rule calls to this rule will be logged.
	/// </summary>
	public class TraceDecorator : IRuleDecorator
	{
		protected internal string m_name="trace";
		protected internal bool m_enabled=true;
		protected internal TraceLevels m_level=TraceLevels.Normal;
		protected internal bool m_exceptionsOnly=false;
		/// <summary>
		/// The main constructor for the TraceDecorator class.  This is called during configuration
		/// as the rule definition is loaded.
		/// </summary>
		/// <param name="name">The name of the decorator???</param>
		/// <param name="val">True/False - If True logging is enabled for this rule.</param>
		/// <param name="extraInfo">N/A</param>
		public TraceDecorator(string name, string val, object extraInfo)
		{
			m_name = name;
			try
			{
				m_enabled = bool.Parse(val);
			}
			catch(Exception)
			{
				throw new Swaf.Config.BadConfigException("Invalid trace attribute value on business rule definition");
			}
		}
		protected void initOptionalAttributes(IRunningRule info)
		{
			try
			{
				m_level = (TraceLevels) TraceLevels.Parse(typeof(TraceLevels),info.decoratorValue("traceLevel",TraceLevels.Normal.ToString()), true);
			}
			catch(Exception)
			{
				throw new Swaf.Config.BadConfigException("Invalid traceLevel attribute value on business rule definition");
			}
			try
			{
				m_exceptionsOnly = bool.Parse(info.decoratorValue("traceExceptionsOnly","false"));
			}
			catch(Exception)
			{
				throw new Swaf.Config.BadConfigException("Invalid traceExceptionsOnly attribute value on business rule definition");
			}

		}
		#region IRuleDecorator Members

		public bool preRuleExecution(IRunningRule info)
		{
			initOptionalAttributes(info);
			return true;
		}

		public void postRuleExecution(IRunningRule info, ref object ruleReturn, ref Exception ruleException)
		{
			object parm=null;
			object parms = info.inputParams;
			System.Type parmType;
			//if the option has been set to log exceptions only and there is no exception
			//we don't need to process any further.
			if (!m_enabled || (m_exceptionsOnly && ruleException == null))
				return;

			StringBuilder buffer = new StringBuilder();
			FlexiMap map = new FlexiMap();
			
			string newLine = Environment.NewLine;
			string parmValue="";
			try
			{
				map.put("ruleName",info.Info.Name);
				if (parms == null)
					map.put("params","");
				else if (parms.GetType() == typeof(object[]))
				{
					object[] inputParams = (object[]) info.inputParams;
					int parmCount = inputParams.Length;
					for (int parmIndex =0;parmIndex<parmCount;parmIndex++)
					{
						parm = inputParams[parmIndex];
						parmType = parm.GetType();
						parmValue = getParmValue(parm,parmType);
						buffer.Append(string.Format("	Param[{0}]: Type=[{1}]  Value=[{2}]{3}",parmIndex,parmType.FullName,parmValue,newLine));  
					}
					map.put("params",buffer.ToString());
				}
				else
				{
					parm = parms;
					parmType = parm.GetType();
					parmValue = getParmValue(parm,parmType);
					map.put("param",string.Format("	Param: Type=[{0}]  Value=[{1}]{2}",parmType.FullName,parmValue,newLine));  
				}
				if (ruleException == null)
				{
					if (ruleReturn != null)
						map.put("results",string.Format("	Results of call were: Type=[{0}]  Value=[{1}]{2}",ruleReturn.GetType().FullName,getParmValue(ruleReturn,ruleReturn.GetType()),newLine));
					else
						map.put("results",string.Format("	Results of call were: No results returned{0}",newLine));

				}
				else
				{
					map.put("results",string.Format("	Exception occurred during rule execution. Exception info was: {0}{1}",ruleException.ToString(),newLine));
				}
				Application.currentApp.Trace.write(m_level,map);
			}
			catch(Exception e)
			{
				Application.currentApp.Log.println("Exeception logging results of rule call [{0}]: {1}",info.Info.Name,e.ToString());
			}
		}
		protected string getParmValue(object parm, Type parmType)
		{
			string parmValue="";
			parmValue = "";
			if (parm != null)
			{
				if (parmType==typeof(IBizObj))
				{
					parmValue = ((IBizObj) parm).Xml;
			
				}
				else if (parmType == typeof(IBizObjList))
				{
					parmValue = ((IBizObjList) parm).Xml;
				}
				else
				{
					parmValue = parm.ToString();
				}
			}
			else
			{
				parmValue = "<Null>";
			}
			return parmValue;
		}

		#endregion

		#region IDecorator Members

		public object decorateInstance(object theInst)
		{
			return theInst;
		}

		public string Value
		{
			get
			{
				return m_level.ToString();
			}
		}

		public string Name
		{
			get
			{
				return m_name;
			}
		}

		public bool IsStandin
		{
			get
			{
				return true;
			}
		}

		#endregion
	}
}
